#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试 GTest 扩展功能
"""


from tests.pytests.helpers.codegen_helpers import (
    compile_chunk,
    assert_code_contains,
    compile_source,
)


def test_basic_test_decorator():
    """测试基本的 @test 装饰器"""
    # 创建测试源文件

    test_source = """
from gtest import test, EXPECT_EQ

@test("MathTest", "Addition")
def test_addition():
    x: int = 1 + 1
    a = [1, 2, 3]
    EXPECT_EQ(x, 2)
"""

    cpp = compile_chunk(test_source)

    # 检查是否包含 GTest 宏
    assert_code_contains(
        cpp,
        """
        TEST(MathTest, Addition) {
            int x = 1 + 1;
            mc::array<int> a = {1, 2, 3};
            EXPECT_EQ(x, 2);
        }
        """,
    )


def test_fixture_test_decorator():
    """测试 @fixture_test 装饰器"""
    # 创建测试源文件
    test_source = """
from gtest import fixture, EXPECT_EQ, EXPECT_TRUE, EXPECT_FALSE
from mc.types import int32_t

@fixture("MyFixture")
class MyFixture:
    def __init__(self):
        self._x: int32_t = 42

@fixture("MyFixture", "TestMethod")
def test_with_fixture(self: MyFixture):
    x: int32_t = 43
    EXPECT_EQ(self._x, x)
"""

    # 编译
    hpp, cpp = compile_source(test_source)
    header = """
        class MyFixture : public testing::Test {
        public:
            MyFixture();
        private:
            int32_t _x;
        };
    """
    source = """
        TEST_F(MyFixture, TestMethod) {
            int32_t x = 43;
            EXPECT_EQ(this->_x, x);
        }
        """

    # 检查是否包含 GTest 夹具宏
    assert_code_contains(hpp, header)
    assert_code_contains(cpp, source)
    assert "#include <gtest/gtest.h>" in hpp
    assert "#include <cstdint>" in hpp


def test_default_parameters():
    """测试默认参数"""
    # 创建测试源文件
    test_source = """
from gtest import test, EXPECT_EQ

@test
def simple_test():
    x: int = 1
    EXPECT_EQ(x, 1);
"""

    # 编译
    cpp = compile_chunk(test_source)

    # 验证生成的 C++ 代码
    assert_code_contains(
        cpp,
        """
        TEST(DefaultTestSuite, simple_test) {
            int x = 1;
            EXPECT_EQ(x, 1);
        }
        """,
    )


def test_multiple_tests():
    """测试多个测试函数"""
    # 创建测试源文件
    test_source = """
from gtest import test, fixture, EXPECT_EQ

@test("Suite1", "Test1")
def first_test():
    x: int = 1
    EXPECT_EQ(x, 1)

@test("Suite1", "Test2")
def second_test():
    y: int = 2
    EXPECT_EQ(y, 2)

@fixture("Fixture1", "FixtureTest")
def fixture_test(self: Fixture1):
    z: int = 3
    EXPECT_EQ(z, 3)
"""

    # 编译
    cpp = compile_chunk(test_source)

    assert_code_contains(
        cpp,
        """
        TEST(Suite1, Test1) {
            int x = 1;
            EXPECT_EQ(x, 1);
        }
        """,
    )
    assert_code_contains(
        cpp,
        """
        TEST(Suite1, Test2) {
            int y = 2;
            EXPECT_EQ(y, 2);
        }
        """,
    )
    assert_code_contains(
        cpp,
        """
        TEST_F(Fixture1, FixtureTest) {
            int z = 3;
            EXPECT_EQ(z, 3);
        }
        """,
    )


def test_test_f_fixture_this_pointer():
    """测试 TEST_F 中 self 被正确转换为 this->"""
    test_source = """
from gtest import test_f, fixture, EXPECT_EQ
from mc.types import int32_t

@fixture()
class MathFixture:
    def __init__(self):
        self.value: int32_t = 10

    def get_value(self) -> int32_t:
        return self.value

    def is_even(self, value: int32_t) -> bool:
        return value % 2 == 0

@test_f("MathFixture", "TestThisPointer")
def test_this_pointer(self: MathFixture):
    result: int32_t = self.get_value()
    EXPECT_EQ(result, 10)
    EXPECT_TRUE(self.is_even(4))
"""

    hpp, cpp = compile_source(test_source)

    assert_code_contains(hpp, "#include <gtest/gtest.h>")
    assert_code_contains(
        hpp,
        """
        class MathFixture : public testing::Test {
        public:
            MathFixture();
            int32_t get_value();
            bool is_even(int32_t value);
        public:
            int32_t value;
        };
        """,
    )
    assert_code_contains(
        cpp,
        """
        MathFixture::MathFixture() {
            this->value = 10;
        }
        int32_t MathFixture::get_value() {
            return this->value;
        }
        bool MathFixture::is_even(int32_t value) {
            return value % 2 == 0;
        }
        TEST_F(MathFixture, TestThisPointer) {
            int32_t result = this->get_value();
            EXPECT_EQ(result, 10);
            EXPECT_TRUE(this->is_even(4));
        }
        """,
    )


def test_gtest_main_function():
    """测试命名空间模块的导入和使用（在 @main 函数中）"""
    test_source = """
from gtest.testing import InitGoogleTest
from mc.types import Pointer, char_ptr
from mcpy.decorators import main
from gtest import RUN_ALL_TESTS

@main()
def main_func(argc: int, argv: Pointer[char_ptr]):
    InitGoogleTest(argc, argv)
    return RUN_ALL_TESTS()
"""

    hpp, cpp = compile_source(test_source)

    assert_code_contains(hpp, "#include <gtest/gtest.h>")
    assert_code_contains(
        cpp,
        """
        int main(int argc, char** argv) {
            testing::InitGoogleTest(&argc, argv);
            return RUN_ALL_TESTS();
        }""",
    )


def test_gtest_import_submodule():
    """测试使用子模块 testing 导入命名空间模块"""
    test_source = """
from gtest import testing, RUN_ALL_TESTS
from mc.types import Pointer, char_ptr
from mcpy.decorators import main

@main()
def main_func(argc: int, argv: Pointer[char_ptr]):
    testing.InitGoogleTest(argc, argv)
    return RUN_ALL_TESTS()
"""

    hpp, cpp = compile_source(test_source)

    assert_code_contains(hpp, "#include <gtest/gtest.h>")
    assert_code_contains(
        cpp,
        """
        int main(int argc, char** argv) {
            testing::InitGoogleTest(&argc, argv);
            return RUN_ALL_TESTS();
        }""",
    )


def test_async_test_function():
    """测试异步测试函数的代码生成，验证 ensure_future 自动导入和正确生成

    测试要点：
    1. 异步测试函数不需要手动导入 ensure_future
    2. 自动导入功能应该自动添加 ensure_future 的导入
    3. ensure_future 应该被正确识别并生成 mcpy::ensure_future
    """
    # 注意：这里没有手动导入 ensure_future，应该由处理器自动添加
    test_source = """
from gtest import test, EXPECT_EQ

@test("AsyncTest", "BasicAsync")
async def test_basic_async():
    async def get_value() -> int:
        return 42
    
    result = await get_value()
    EXPECT_EQ(result, 42)
"""

    cpp = compile_chunk(test_source)
    assert_code_contains(
        cpp,
        """
    TEST(AsyncTest, BasicAsync) {
        mcpy::ensure_future(${w+}test_basic_async{}()).get();
    }   
    """,
        use_markers=True,
    )
